package com.future.service.Impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.future.allUtils.enums.ClassEnum;
import com.future.allUtils.enums.OptionOrder;
import com.future.allUtils.enums.QuestionType;
import com.future.allUtils.enums.RoleEnum;
import com.future.allUtils.utils.CacheClient;
import com.future.allUtils.utils.JudgeUtil;
import com.future.allUtils.utils.SecurityUtils;
import com.future.domain.*;
import com.future.domain.DTO.*;
import com.future.domain.vo.*;
import com.future.mapper.*;
import com.future.service.*;

import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.future.allUtils.constants.RedisCacheConstants.*;
import static com.future.allUtils.constants.RedisConstants.*;

@Slf4j
@Service
public class IQuestionnaireServiceImpl extends ServiceImpl<QuestionnaireMapper, Questionnaire> implements IQuestionnaireService {
  //  @Value("${server.port}")
    private String port = "9090";
   // @Value("${server.address}")
    private String address = "47.110.147.12";
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IQuestionService questionService;
    @Resource
    private IOptionService optionService;
    @Autowired
    private CacheClient cacheClient;
    @Autowired
    private IAnswerSheetService answerSheetService;
    @Autowired
    private QuestionnaireMapper questionnaireMapper;
    @Autowired
    private IAnswerDetailService answerDetailService;
    @Autowired
    private JudgeUtil judgeUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AnswerSheetMapper answerSheetMapper;
    @Autowired
    private QuestionMapper questionMapper;
    @Resource
    private AverageScoreMapper averageScoreMapper;
    @Resource
    private QuestionnaireResponseMapper questionnaireResponseMapper;
    @Autowired
    private UserClassMapper userClassMapper;
    @Resource
    private HealthDetailMapper healthDetailMapper;
    @Autowired
    private NotificationService notificationService;
    @Autowired
    private ChatRoomMemberMapper chatRoomMemberMapper;
    @Autowired
    private UserService userService;
    @Resource
    private AdminService adminService;



    /**
     * 发布问卷
     * @param questionnaireDTO问卷信息
     * @return Result
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result publish(QuestionnaireDTO questionnaireDTO) {
        log.info("questionnaireDTO:{}", questionnaireDTO);
        //获取当前登录用户的信息
        LoginUserDetails currentUser = SecurityUtils.getCurrentUser();
        Long currentUserId = currentUser.getUser().getId();
        List<Integer> userRole = userMapper.getUserRole(currentUserId);
        //下发班级 ： 心理医生所有班级 ，老师：自己管理的班级
        String className = "";
        if(!userRole.contains(3)){
            Long classIdByUserId = adminService.getClassIdByUserId(currentUserId);
            if(classIdByUserId != null){
                className = ClassEnum.getClassNameByClassId(classIdByUserId.intValue());
            }else{
                className = "";
            }
        }
        //检查参数
        String msg = checkQuestionnaire(questionnaireDTO);
        if(!msg.equals("ok")) {
            return Result.fail(msg);
        }
        //设置问卷的基本参数
        Questionnaire questionnaire = new Questionnaire();
        BeanUtil.copyProperties(questionnaireDTO, questionnaire);
        questionnaire.setCreatorId(currentUser.getUser().getId()).setCreatorRole("教师").setClassName(className);
        try {
            //存储问卷
            this.save(questionnaire);
            //赋值问题列表和选项列表

            int totalScore= saveQuestion(questionnaireDTO, questionnaire.getId());
            //存总分
            UpdateWrapper<Questionnaire> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", questionnaire.getId());
            updateWrapper.set("total_score", totalScore);
            questionnaireMapper.update(questionnaire, updateWrapper);
            //如果是发布状态,需要存问卷回答详情表
            if(questionnaireDTO.getPublishStatus() == 1){
                //存问卷回答详情表
                QuestionnaireResponse questionnaireResponse = new QuestionnaireResponse();
                //根据班级查询班级人数 : 应该作答人数
                int totalNum = 0;
                if(className == null || "".equals(className)) {
                    totalNum = userClassMapper.selectCount(null).intValue();
                    log.info("totalNum:{}",totalNum);
                }else {
                    String[] split = className.split(",");
                    List<Integer> collect = Arrays.stream(split).map(s -> {
                        return ClassEnum.valueOf(s).getClassId();
                    }).collect(Collectors.toList());
                    totalNum= userClassMapper.selectCount(new LambdaQueryWrapper<UserClass>().in(UserClass::getClassId, collect)).intValue();
                }
                questionnaireResponseMapper.insert(questionnaireResponse.setQuestionnaireId(questionnaire.getId()).setTotalNum(totalNum));

                List<Long> userIds=new ArrayList<>();
                if(className == null || "".equals(className)){
                    //如果班级名为空的话,通知所有用户填写调查问卷
                    QueryWrapper<UserClass> queryWrapper=new QueryWrapper<>();
                    List<UserClass> userClasses = userClassMapper.selectList(queryWrapper);
                    userIds= userClasses.stream()
                            .map(UserClass::getUserId)
                            .collect(Collectors.toList());
                }else{
                    String[] split = className.split(",");
                    for(String s:split) {
                        List<Long> Ids= chatRoomMemberMapper.selectUserIdByclassName(s);
                        userIds.addAll(Ids);
                    }
                }
                if(userIds!=null&&!userIds.isEmpty())
                    notificationService.sendQuestionnaire(userIds,questionnaire.getId(),
                            "《"+questionnaire.getTitle()+"》："+questionnaire.getDescription());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
        return Result.ok("发布成功");
    }
    /**
     * 更新问卷
     * @param questionnaireDTO问卷信息
     * @param questionnaireId问卷id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateQuestionnaire(QuestionnaireDTO questionnaireDTO, Long questionnaireId) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        try{
            questionnaireMapper.deleteById(questionnaireId);
            publish(questionnaireDTO);
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw e;
        }
        return Result.ok("更新成功");
    }

    @Transactional(rollbackFor = Exception.class)
    public Result updateQuestionnaire1(QuestionnaireVO questionnaireVO) {


        Long questionnaireId = Long.valueOf(questionnaireVO.getQuestionnaireId());
        log.info("questionnaireVO:{}", questionnaireVO);

        Long currentUserId = SecurityUtils.getCurrentUserId();
        //1.检查参数
        String msg = checkQuestionnaireVO(questionnaireVO);
        if(!msg.equals("ok")) {
            return Result.fail(msg);
        }
        //2.更新问卷
        Questionnaire questionnaire = BeanUtil.copyProperties(questionnaireVO, Questionnaire.class);
        boolean b = updateById(questionnaire.setId(questionnaireId));
        if(!b) {
            return Result.fail("更新失败");
        }
        //3.更新问题和选项
        //原本的问题id
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("questionnaire_id", questionnaireId);
        List<Long> DBQIds = questionMapper.selectList(queryWrapper).stream().map(question -> {
            return  question.getId();
        }).collect(Collectors.toList());
        //原本选项的id
        QueryWrapper<Option> optionQueryWrapper = new QueryWrapper<>();
        optionQueryWrapper.in(DBQIds!=null && !DBQIds.isEmpty(),"question_id",DBQIds);
        List<Long> DBOIds = optionService.getBaseMapper().selectList(optionQueryWrapper).stream().map(option -> {
            return  option.getId();
        }).collect(Collectors.toList());
        //如今的问题id
        List<Long> Qids = questionnaireVO.getQuestions().stream().map(question->question.getId()).filter(id -> id != null).mapToLong(Long::valueOf).boxed().collect(Collectors.toList());
        log.info("DBQIds:{}",DBQIds);
        log.info("Qids:{}",Qids);
        //删除已经不存在的问题和对应的选项
        if (Qids ==null ||Qids.isEmpty() ) {
            questionMapper.deleteBatchIds(DBQIds);
        }else{
            //删除不存在的问题
            List<Long> deleteIds = DBQIds.stream().filter(id -> !Qids.contains(id)).collect(Collectors.toList());
            log.info("deleteIds:{}", deleteIds);
            if (deleteIds != null && !deleteIds.isEmpty()) {
                questionMapper.deleteBatchIds(deleteIds);
            }
        }
        try {
            List<Long> collectOIds = new ArrayList<>();
            //添加 原先不存在的问题和选项  并更新存在的问题
            questionnaireVO.getQuestions().forEach(question -> {
                Question q = BeanUtil.copyProperties(question, Question.class);
                 //添加 原先不存在的问题
                log.info("question:{}",question);
                log.info("question.getId():{}",question.getId());
                if(question.getId() == null){
                    long qID = IdUtil.getSnowflakeNextId();
                    q.setId(qID);
                    q.setQuestionnaireId(questionnaireId);
                    questionMapper.insert(q);
                    List<Option> collect1 = question.getOptions().stream().map(option -> {
                         Option o = BeanUtil.copyProperties(option, Option.class);
                         o.setQuestionId(qID);
                         //存入redis
                         stringRedisTemplate.opsForZSet().add(OPTION_SCORE_KEY+questionnaireId,qID+":"+option.getSortOrder().getDescription(), option.getScore());
                         return o;
                    }).collect(Collectors.toList());
                    log.info("collect1:{}",collect1);
                    optionService.saveBatch(collect1);
                }else {
                    //存在的问题
                    //更新存在的问题
                    questionMapper.updateById(q);
                    //更新存在的选项 存在的选项 、不存在的选项、需要删除的选项
                    question.getOptions().forEach(option -> {
                        Option o = BeanUtil.copyProperties(option, Option.class);
                        if(option.getId() == null){
                            //添加不存在的选项
                            o.setQuestionId(Long.valueOf(question.getId()));
                            optionService.save(o);
                        }else{
                            //更新存在的选项
                            optionService.updateById(o);
                            //收集所有选项的id
                            collectOIds.add(option.getId());
                        }
                        stringRedisTemplate.opsForZSet().add(OPTION_SCORE_KEY+questionnaireId,question.getId()+":"+option.getSortOrder().getDescription(), option.getScore());
                    });
                }
             });
            //删除不存在的选项
            if(DBOIds!=null&&!DBOIds.isEmpty()) {
                List<Long> deleteOIds = DBOIds.stream().filter(id -> !collectOIds.contains(id)).collect(Collectors.toList());
                log.info("deleteOIds:{}", deleteOIds);
                if (deleteOIds != null && !deleteOIds.isEmpty()) {
                    optionService.getBaseMapper().deleteBatchIds(deleteOIds);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
        //3.更新缓存
        stringRedisTemplate.delete(QUESTIONNAIRE_INFO_PREFIX+currentUserId);
        stringRedisTemplate.delete(QUESTIONNAIRE_INFO_PREFIX + questionnaireId);
        if(questionnaireVO.getPublishStatus() ==1){
            //计算班级人数
            Long currentUserId1 = SecurityUtils.getCurrentUserId();
            List<Integer> userRole = userMapper.getUserRole(currentUserId1);
            long totalNum =0;
            if(userRole.contains(3)){
                totalNum=userClassMapper.selectCount(null);
            }else{
                Long classIdByUserId = adminService.getClassIdByUserId(currentUserId1);
                totalNum=userClassMapper.selectCount(new QueryWrapper<UserClass>().eq("class_id",classIdByUserId));
            }
            //看看有没有问卷回答详情表
            QuestionnaireResponse questionnaireResponse = questionnaireResponseMapper.selectOne(new QueryWrapper<QuestionnaireResponse>().eq("questionnaire_id",questionnaireId));
            //没有，添加问卷详情表
            if(ObjectUtil.isNull(questionnaireResponse)){
                questionnaireResponse = new QuestionnaireResponse();
                questionnaireResponse.setQuestionnaireId(questionnaireId).setTotalNum((int) totalNum);
                questionnaireResponseMapper.insert(questionnaireResponse);
            }else{
                //4.有的话更新健康情况表
                questionnaireResponse.setAnsweredNum(0);
                questionnaireResponse.setExpiredAt(questionnaireVO.getExpiredAt())
                        .setStartAt(questionnaireVO.getStartAt())
                        .setQuestionnaireId(Long.valueOf(questionnaireVO.getQuestionnaireId()))
                        .setAverageScore(0)
                ;
                questionnaireResponseMapper.update(questionnaireResponse,new QueryWrapper<QuestionnaireResponse>().eq("questionnaire_id",questionnaireId));
            }
            //5.删除答卷
            answerSheetMapper.delete(new QueryWrapper<AnswerSheet>().eq("questionnaire_id",questionnaireId));
            //6.删除缓存
            cacheClient.deleteByPattern(ANSWER_SHEET_PREFIX+questionnaireId+":*");
            cacheClient.deleteByPattern(USER_QUESTIONNAIRE_KEY+"*");
        }

        return Result.ok("更新成功");
    }
    /*
    * 存储问题和选项
    * */
    @Transactional(rollbackFor = Exception.class)
    public  int saveQuestion(QuestionnaireDTO questionnaireDTO,Long questionnaireId){
        final Integer[] totalScore = {0};
        try {
            List<QuestionDTO> questions = questionnaireDTO.getQuestions();
            List<Question> questionList = new ArrayList<>();
            List<Option> optionList = new ArrayList<>();

            for (QuestionDTO questionDTO : questions) {
                Question question = new Question();
                BeanUtil.copyProperties(questionDTO, question);
                //  生成问题id
                long questionID = IdUtil.getSnowflakeNextId();
                log.info("questionID:{}",questionID);
                question.setQuestionnaireId(questionnaireId);
                question.setId(questionID);
                //添加到列表中
                questionList.add(question);
                final int[] score = {0};

                if(question.getQuestionType().equals(QuestionType.SINGE)){
                    //单选题
                    questionDTO.getOptions().forEach(optionDTO -> {
                        Option option = new Option();
                        BeanUtil.copyProperties(optionDTO, option);
                        option.setQuestionId(questionID);
                        optionList.add(option);
                        score[0] =Math.max(score[0],optionDTO.getScore());
                        //缓存选项的分数
                        stringRedisTemplate.opsForZSet()
                                .add(OPTION_SCORE_KEY + questionnaireId,
                                        questionID+":"+ optionDTO.getSortOrder(),
                                        optionDTO.getScore());
                    });
                }else{
                    questionDTO.getOptions().forEach(optionDTO -> {
                        Option option = new Option();
                        BeanUtil.copyProperties(optionDTO, option);
                        option.setQuestionId(questionID);
                        optionList.add(option);
                        totalScore[0] += optionDTO.getScore();
                        //缓存选项的分数
                        stringRedisTemplate.opsForZSet()
                                .add(OPTION_SCORE_KEY + questionnaireId,
                                        questionID+":"+ optionDTO.getSortOrder(),
                                        optionDTO.getScore());
                    });
                }
                totalScore[0] += score[0];
            }
            questionService.saveBatch(questionList);
            optionService.saveBatch(optionList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return totalScore[0];
    }
    /**
     *  检查问卷参数
     * @param questionnaireDTO
     * @return
     */
    private  String checkQuestionnaire(QuestionnaireDTO questionnaireDTO ) {
        if(ObjectUtil.isNull(questionnaireDTO.getTitle())){
            return "请输入问卷标题";
        }
        if(ObjectUtil.isNull(questionnaireDTO.getDescription())){
            return "请输入问卷描述";
        }
         if (ObjectUtil.isNull(questionnaireDTO.getStartAt())  ) {
             return "请选择问卷开始时间";
         }
         if (ObjectUtil.isNull(questionnaireDTO.getExpiredAt())) {
             return"请选择问卷截止时间";
         }
         if (questionnaireDTO.getStartAt().isAfter(questionnaireDTO.getExpiredAt())) {
             return "问卷开始时间不能晚于问卷截止时间";
         }
         if (questionnaireDTO.getQuestions().size() < 1) {
             return "请添加问题";
         }
         if(questionnaireDTO.getPublishStatus() !=0 && questionnaireDTO.getPublishStatus() !=1){
             return "问卷状态设置错误 1：发布 0：暂存草稿";
         }
         //检查问题的类型
         for (QuestionDTO questionDTO : questionnaireDTO.getQuestions()) {
             if (questionDTO.getQuestionType().equals(QuestionType.SINGE)) {
                 if (questionDTO.getOptions().size() < 2) {
                     return "单选题必须有两个选项";
                 }
             }
             if (questionDTO.getQuestionType().equals(QuestionType.MULTIPLE)) {
                 if (questionDTO.getOptions().size() < 3) {
                     return "多选题必须有三个选项";
                 }
             }
             Set<Integer> set =new HashSet<>();
             questionDTO.getOptions().forEach(optionDTO -> {
                 set.add(optionDTO.getSortOrder().getValue());
             });
             if(set.size() != questionDTO.getOptions().size()){
                 return "选项排序不能重复";
             }
         }
         return "ok";
     }
    private  String checkQuestionnaireVO (QuestionnaireVO questionnaireDTO ) {
        if(ObjectUtil.isNull(questionnaireDTO.getTitle())){
            return "请输入问卷标题";
        }
        if(ObjectUtil.isNull(questionnaireDTO.getDescription())){
            return "请输入问卷描述";
        }
        if (ObjectUtil.isNull(questionnaireDTO.getStartAt())  ) {
            return "请选择问卷开始时间";
        }
        if (ObjectUtil.isNull(questionnaireDTO.getExpiredAt())) {
            return"请选择问卷截止时间";
        }
        if (questionnaireDTO.getStartAt().isAfter(questionnaireDTO.getExpiredAt())) {
            return "问卷开始时间不能晚于问卷截止时间";
        }
        if (questionnaireDTO.getQuestions().size() < 1) {
            return "请添加问题";
        }
        if(questionnaireDTO.getPublishStatus() !=0 && questionnaireDTO.getPublishStatus() !=1){
            return "问卷状态设置错误 1：发布 0：暂存草稿";
        }
        //检查问题的类型
        for (CacheQuestionDTO questionDTO : questionnaireDTO.getQuestions()) {
            if (questionDTO.getQuestionType().equals(QuestionType.SINGE)) {
                if (questionDTO.getOptions().size() < 2) {
                    return "单选题必须有两个选项";
                }
            }
            if (questionDTO.getQuestionType().equals(QuestionType.MULTIPLE)) {
                if (questionDTO.getOptions().size() < 3) {
                    return "多选题必须有三个选项";
                }
            }
            Set<Integer> set =new HashSet<>();
            questionDTO.getOptions().forEach(optionDTO -> {
                set.add(optionDTO.getSortOrder().getValue());
            });
            if(set.size() != questionDTO.getOptions().size()){
                return "选项排序不能重复";
            }
        }
        return "ok";
    }

    /**
     *   提交问卷，进行评分和建议
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result judge(List<AnswerDetailDTO> answerList, String questionnaireId) throws Exception {
        Long questionnaireIdLong  = Long.valueOf(questionnaireId);
        log.info("answerList:{}",answerList);
        //1.获取当前用户
        LoginUserDetails currentUser = SecurityUtils.getCurrentUser();
        Long currentUserId = currentUser.getUser().getId();
        String className = userMapper.getClassName(currentUserId);

        //检查用户是否已经提交过了
        List<Long> finishedQID = cacheClient.getFinishedQID(currentUserId);
        if(finishedQID.contains(questionnaireIdLong)){
            Object o = stringRedisTemplate.opsForHash().get(ANSWER_SHEET_PREFIX + questionnaireId, currentUserId.toString());
             // 2. 使用JSON工具反序列化为对象
            GetAnswerSheetVO answersheet = JSONUtil.toBean(JSONUtil.toJsonStr(o), GetAnswerSheetVO.class);
            return Result.fail("已经提交过了").setData(answersheet);
        }


        //计算得分
        Double total = score(answerList, questionnaireIdLong);

        QuestionnaireVO questionnaire = cacheClient.queryWithLogicalExpire(QUESTIONNAIRE_INFO_PREFIX, questionnaireId, QuestionnaireVO.class, id ->
                questionnaireMapper.selectQuestionnaireById(questionnaireIdLong), CACHE_QUESTIONNAIRE_TTL,TimeUnit.DAYS);
        if(questionnaire==null){
            questionnaire = questionnaireMapper.selectQuestionnaireById(questionnaireIdLong);
        }
        //检查答案数据
        String check = judgeAnswer(answerList, questionnaire);
        if(!"success".equals(check)){
            return Result.fail(check);
        }
        log.info("total:{}",(int) ((total.doubleValue()/questionnaire.getTotalScore())*100));
        //更新问卷作答详情表
        UpdateWrapper<QuestionnaireResponse> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("questionnaire_id",questionnaireId)
                .setSql("score = score+"+total.doubleValue())
                .setSql("answered_num = answered_num+1");
        questionnaireResponseMapper.update(new QuestionnaireResponse().setQuestionnaireId(questionnaireIdLong),updateWrapper);

        //存入answerSheet
        AnswerSheet answerSheet = new AnswerSheet();
        boolean save = answerSheetService.save(
                answerSheet
                        .setQuestionnaireId(questionnaireIdLong)
                        .setSuggestion(judgeUtil.judgeSuggestion(total.intValue()))
                        .setCompletedAt(LocalDateTime.now())
                        .setCreatedAt(LocalDateTime.now())
                        .setTotalScore(total.intValue())
                        .setUserId(currentUserId)
        );
        log.info("creatorName,",questionnaire.getCreatorName());

        //redis 缓存
        GetAnswerSheetVO answerSheetVO = new GetAnswerSheetVO();
        answerSheetVO
                .setUserId(currentUserId)
                .setAnswerList(answerList)
                .setCompletedAt(LocalDateTime.now())
                .setRealName(currentUser.getUser().getRealName())
                .setSuggestion(judgeUtil.judgeSuggestion(total.intValue()))
                .setTotalScore(total.intValue())
                .setClassName(className)
                .setAvatar(currentUser.getUser().getAvatar())
                .setAnswerSheetId(answerSheet.getId());
        SAnswerSheetVo sAnswerSheetVo1 = BeanUtil.copyProperties(answerSheetVO, SAnswerSheetVo.class);
        sAnswerSheetVo1.setCreatorName(questionnaire.getCreatorName()).setTotalScore(questionnaire.getTotalScore()).setScore(total.intValue()).setCompletedAt(LocalDateTime.now());

        //存储回答过的问卷的id 和答卷
        stringRedisTemplate.opsForSet().add(USER_QUESTIONNAIRE_KEY + currentUserId, questionnaireId.toString());
        stringRedisTemplate.opsForZSet().add(ANSWER_SHEET_PREFIX+currentUserId,
                JSONUtil.toJsonStr(sAnswerSheetVo1),
                LocalDateTime.now()
                        .atZone(ZoneId.systemDefault())
                        .toInstant()
                        .toEpochMilli());
        //保存答案详情数据库中
        List<AnswerDetail> answerDetails = answerList.stream().map(answerDTO -> {
                AnswerDetail answerDetail = new AnswerDetail();
                BeanUtil.copyProperties(answerDTO, answerDetail);
                answerDetail.setAnswerSheetId(answerSheet.getId());
                return answerDetail;
            }).collect(Collectors.toList());
            //  批量保存答案详情
            boolean b = answerDetailService.saveBatch(answerDetails);
            if(b){
                //更新或者存储健康情况表
                QueryWrapper<HealthDetail> healthDetailQueryWrapper = new QueryWrapper<>();
                healthDetailQueryWrapper.eq("user_id", currentUserId);
                HealthDetail healthDetail = healthDetailMapper.selectOne(healthDetailQueryWrapper);
                if(healthDetail!=null){
                    healthDetail.setScore((int) ((total.doubleValue()/questionnaire.getTotalScore())*100)+healthDetail.getScore());
                    healthDetail.setTotalSize(healthDetail.getTotalSize()+1);
                    log.info("healthDetail:{}",healthDetail);
                    healthDetail.setCompletedAt(LocalDateTime.now());
                    healthDetailMapper.updateById(healthDetail);
                }else{
                    healthDetailMapper.insert(new HealthDetail()
                            .setScore((int) ((total.doubleValue()/questionnaire.getTotalScore())*100))
                            .setUserId(currentUserId)
                            .setCompletedAt(LocalDateTime.now())
                            .setTotalSize(1)
                    );
                }
                return Result.ok(answerSheetVO);
            }
            return Result.fail("提交失败");
    }
    private String judgeAnswer(List<AnswerDetailDTO> answerList,QuestionnaireVO questionnaire){
        List<CacheQuestionDTO> questions = questionnaire.getQuestions();
        List<Long> collect = questions.stream().map(question -> question.getId()).mapToLong(Long::valueOf).boxed().collect(Collectors.toList());
        if(!answerList.stream().map(AnswerDetailDTO::getQuestionId).mapToLong(Long::valueOf).boxed().collect(Collectors.toList()).containsAll(collect)){
            return "请填写完整";
        }
        for(AnswerDetailDTO answerDTO : answerList){
            CacheQuestionDTO question = questions.stream().filter(q -> q.getId().equals(answerDTO.getQuestionId())).findFirst().get();
            if(question.getQuestionType() == QuestionType.SINGE){
                if(answerDTO.getSortOrder().trim().split(",").length > 1){
                    return "单选题只能选择一个";
                }
            }
        }
        return "success";
    }



    public Double score(List<AnswerDetailDTO> answerList,Long questionnaireId) throws Exception {
        Double total = 0d;
        for(AnswerDetailDTO answerDTO : answerList){
            String answer = answerDTO.getSortOrder();
            String[] split = answer.trim().split(",");
            for(String option : split){
                try{
                    log.info("option:{}",option);
                    Double score =   stringRedisTemplate.opsForZSet().score(OPTION_SCORE_KEY  + questionnaireId, answerDTO.getQuestionId() + ":" + option);
                    if(score == null){
                        Option option1 = optionService.getBaseMapper().selectOne(new LambdaQueryWrapper<Option>()
                                .eq(Option::getQuestionId, Long.valueOf(answerDTO.getQuestionId()))
                                .eq(Option::getSortOrder, OptionOrder.valueOf(option)));
                        if(option1 == null){
                            //参数传递错误
                            throw new IllegalArgumentException("参数传递错误");
                        }
                        //重建缓存
                        stringRedisTemplate.opsForZSet().addIfAbsent(OPTION_SCORE_KEY  + questionnaireId, answerDTO.getQuestionId() + ":" + option,option1.getScore().doubleValue());
                        score = option1.getScore().doubleValue();
                    }
                    total += score;
                    log.info("score:{}",score);
                }catch (Exception e){
                    //参数传递错误
                     log.error(e.getMessage(), e);
                    throw new Exception(e.getMessage());
                }
            }
        }
        return total;
    }


    /**
     *  获取问卷信息
     * @param questionnaireId 问卷id
     * @return Result
     */
    public Result getQuestionnaire(String questionnaireId) {
        LoginUserDetails currentUser = SecurityUtils.getCurrentUser();
        Long currentUserId = currentUser.getUser().getId();
        Long questionnaireIdLong = Long.valueOf(questionnaireId);
        //  检查问卷是否填写过
        Map<String,Object> map = new HashMap<>();
        //  获取用户角色 : 判断是不是学生
        List<Integer> userRole = userMapper.getUserRole(currentUserId);
        boolean flag=false;
        if(userRole.contains(1) ){
             flag=true;
        }
        //  从缓存中查询问卷信息
        QuestionnaireVO questionnaireVO = cacheClient.queryWithLogicalExpire(QUESTIONNAIRE_INFO_PREFIX, questionnaireId, QuestionnaireVO.class, id ->
                questionnaireMapper.selectQuestionnaireById(Long.valueOf(questionnaireIdLong)), CACHE_QUESTIONNAIRE_TTL,TimeUnit.SECONDS);

        if(questionnaireVO == null){
            questionnaireVO = questionnaireMapper.selectQuestionnaireById(questionnaireIdLong);
            log.info("questionnaireVO:{}",questionnaireVO);
            if(questionnaireVO == null){
                return Result.fail("问卷不存在");
            }
            cacheClient.setWithLogicalExpire(QUESTIONNAIRE_INFO_PREFIX+questionnaireId,questionnaireVO,CACHE_QUESTIONNAIRE_TTL,TimeUnit.DAYS);
        }
        //学生端逻辑 ： 判断是否做过了
        if(flag){
            List<Long> finishedQID = cacheClient.getFinishedQID(currentUserId);
            log.info("finishedQID:{}",finishedQID);

            if(!finishedQID.isEmpty() && finishedQID.contains(questionnaireIdLong)){
                questionnaireVO.setStatus(1);
                GetAnswerSheetVO answerSheetVO = cacheClient.queryWithLogicalExpire(ANSWER_SHEET_PREFIX+questionnaireId+":",currentUserId,GetAnswerSheetVO.class,id->answerSheetMapper.getAnswerSheet(questionnaireIdLong,currentUserId),7L,TimeUnit.DAYS);
                log.info("answerSheetVO:{}",answerSheetVO);
                if(ObjectUtil.isNull(answerSheetVO)){
                    answerSheetVO = answerSheetMapper.getAnswerSheet(questionnaireIdLong,currentUserId);
                    log.info("answerSheetVO:{}",answerSheetVO);
                    cacheClient.setWithLogicalExpire(ANSWER_SHEET_PREFIX+questionnaireId+":"+currentUserId,answerSheetVO,7L,TimeUnit.DAYS);
                }
                map.put("answerSheetVO",answerSheetVO);
            }
        }
        map.put("questionnaireVO",questionnaireVO);
        return Result.ok(map);
    }


    /**
     *   学生端逻辑：
     *   查询接受到的所有的问卷
     */
    @Override
    public Result getAllQuestionnaireByPage(Integer pageNum,Integer pageSize) {
        Integer startIndex = accessPage(pageNum, pageSize);
        if(startIndex ==-1){
            return Result.fail("页码或每页大小传递错误");
        }
        int endIndex = startIndex+pageSize -1;
        //获取当前登录用户的信息
        Long currentUserId = SecurityUtils.getCurrentUserId();
        //获取用户的班级名称
        String  className = userMapper.getClassName(currentUserId);
        if(className==null){
            className="";
        }
        List<Long> finishedQID = cacheClient.getFinishedQID(currentUserId);
        String finalClassName = className;
        List<String> range = stringRedisTemplate.opsForList().range("questionnaire:class:" + finalClassName, startIndex, endIndex);

        List<PageQuestionnaireVOForS> list = questionnaireMapper.getByPage(new HashMap<String,Object>(){
            {
                put("start_index",startIndex);
                put("page_size",pageSize);
                put("class_name", finalClassName);
            }
        });
        list.forEach(item->{
           if(finishedQID.contains(item.getId()))  item.setStatus(1);
        });
        log.info("list:{}",list);
        log.info("ids:{}",finishedQID);
        //总条数
        Long count = questionnaireMapper.count(new HashMap<String,Object>(){
            {
                put("class_name", finalClassName);
                put("publish_status",1);
            }
        });
        //  计算总页数
        int totalPages = (int) Math.ceil(count.doubleValue() / pageSize);
        if(count == 0){
            return Result.ok(new PageDTO<PageQuestionnaireVOForS>().setRows(Collections.emptyList()).setTotalPage(0l).setTotal(0l));
        }
        //  封装分页结果
        PageDTO<PageQuestionnaireVOForS> pageResult = new PageDTO<PageQuestionnaireVOForS>()
            .setRows(list)
            .setTotal(count)
            .setTotalPage((long) totalPages);
        return Result.ok(pageResult);
    }
    /**
     *  处理分页参数
     */
    private Integer accessPage(Integer pageNum,Integer pageSize){
        if(pageNum == null || pageSize == null || pageNum < 1 || pageSize < 1){
            return -1;
        }
        return (pageNum -1)*pageSize;
    }


    @Override
    public Result getAverageScore() {
        List<AverageScore> averageScores = averageScoreMapper.selectList(null);
        return Result.ok(averageScores);
    }

    private List<PageQuestionnaireVOForS> test( int pageNum,int pageSize,String className){
         //1.处理分页参数
         pageNum =  pageNum <1 ? 1 :pageNum;
         pageSize = pageSize <10 ? 1 :pageSize;
         int startIndex =   (pageNum-1) * pageSize;
         int endIndex = startIndex + pageSize -1;
         //2.查询redis
        Set<String> range = stringRedisTemplate.opsForZSet().range(CLASS_QUESTIONNAIRE_PREFIX + className, startIndex, endIndex);
        //2.1 ： redis中为空
        if(range.isEmpty()) {
            //查询数据库 ：
            int finalPageSize = pageSize;
            List<PageQuestionnaireVOForS> list = questionnaireMapper.getByPage(new HashMap<String, Object>() {
                {
                    put("start_index", startIndex);
                    put("page_size", finalPageSize);
                    put("class_name", className);
                }
            });
        }
        return null;
    }




    public Result saveLink(Long questionnaireId) throws UnsupportedEncodingException, UnsupportedEncodingException {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        stringRedisTemplate.opsForValue().set(uuid,questionnaireId.toString(),7l,TimeUnit.DAYS);
        // 对UUID进行URL编码
        String url=HTTP_URL+address+":"+port+"/"+"?link="+uuid;
        return Result.ok(url);
    }

    @Override
    public Result getByLink(String link) throws UnsupportedEncodingException {
        String questionnaireId = stringRedisTemplate.opsForValue().get(link);

        if(questionnaireId == null){
            return Result.fail("链接已失效");
        }
        return  getQuestionnaire(questionnaireId);
    }



    /**
     * 查询草稿
     */
    @Override
    public Result getDraft(Integer pageNum,Integer pageSize) {
        //1.获取当前用户id
        Long currentUserId = SecurityUtils.getCurrentUserId();
        //2.处理分页参数
        Integer startIndex = accessPage(pageNum, pageSize);
        if(startIndex == -1){
            return Result.fail("页码或每页大小参数传递错误");
        }
        int endIndex  = startIndex + pageSize -1;
        log.info("startIndex:{}",startIndex);
        log.info("endIndex:{}",endIndex);
        Page<Questionnaire> page = new Page<>(pageNum, pageSize);

// 执行分页查询
        //查询数据
        List<Questionnaire> questionnaires = cacheClient.queryWithListForPage(QUESTIONNAIRE_INFO_PREFIX, currentUserId, startIndex, endIndex, Questionnaire.class, id -> {
            return questionnaireMapper.selectList(new LambdaQueryWrapper<Questionnaire>()
                    .eq(Questionnaire::getCreatorId, currentUserId)
                    .eq(Questionnaire::getPublishStatus, 0)
                    .orderByDesc(Questionnaire::getCreatedAt)
                    .last("limit "+startIndex+","+endIndex)
            );
        });
        log.info("questionnaires:{}",questionnaires);
        //获取总页数和总条数
        Long size = stringRedisTemplate.opsForList().size(QUESTIONNAIRE_INFO_PREFIX + currentUserId);
        log.info("size:{}",size);
        Long totalPages=0L;
        if(size == 0 && questionnaires.isEmpty()){
            return Result.ok(PageDTO.empty(new Page<>()));
        }else{
            size = questionnaireMapper.selectCount(new LambdaQueryWrapper<Questionnaire>()
                    .eq(Questionnaire::getCreatorId, currentUserId)
                    .eq(Questionnaire::getPublishStatus, 0)
            );
             totalPages = Math.round(Math.ceil((double)size / pageSize));
        }
        return Result.ok(new PageDTO<Questionnaire>()
                .setRows(questionnaires)
                .setTotalPage(totalPages)
                .setTotal(size));
    }
    /**
     *  教师端： 查寻已发布的问卷的列表
     * @param pageNum
     * @param pageSize
     * @param title
     * @return
     */
    @Override
    public Result getPublished(Integer pageNum, Integer pageSize,String title) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        Integer startIndex = accessPage(pageNum, pageSize);
        if(startIndex==-1){
            return Result.fail("参数传递错误");
        }
        // 问卷id   、问卷标题 、问卷描述 、问卷总人数 、问卷已回答人数、问卷平均分
        List<QuestionnaireResponseVOForT> questionnaireResponseVOForTS = questionnaireResponseMapper.selectForT(startIndex, pageSize, currentUserId,title);
        Long total = questionnaireMapper.selectCount(new QueryWrapper<Questionnaire>()
                .eq("creator_id", currentUserId)
                .eq("is_published", 1)
                .like(title!=null && title != " ","title", title));
        log.info("total:{}",total);
        PageDTO<QuestionnaireResponseVOForT> pageDTO = new PageDTO<>();
        pageDTO.setRows(questionnaireResponseVOForTS).setTotal(total).setTotalPage(Math.round(Math.ceil((double)total / pageSize)));
        return Result.ok(pageDTO);
    }

    @Override
    public Result deleteById(Long id) {
        boolean b = removeById(id);
        stringRedisTemplate.delete(QUESTIONNAIRE_INFO_PREFIX + id);

        if(!b){
            return Result.fail("删除失败");
        }
        return Result.ok("删除成功");
    }


}


